﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEditor;
using UnityEngine;
using xuni;

namespace xab
{
    public static class Utils
    {
        public const string Bundle_Ext = ".bin";

        //todo: 放到VersionUtils?
        public static void CreateVersionsFile(StringBuilder sb, string buildOutputDir)
        {
            var di = new DirectoryInfo(buildOutputDir);
            var allFileInfos = di.GetFiles("*.*", SearchOption.AllDirectories);

            Debug.Log($"CreateVersionsFile: out: {buildOutputDir}, fileCt: {allFileInfos.Length}");
            if (allFileInfos.Length <= 0)
                return;

            var resVerFile = sb.Append(buildOutputDir).Append("ResVer.bin").ToString();
            sb.Clear();
            var resVerStr = "1";
            if (File.Exists(resVerFile))
            {
                try
                {
                    var lines = File.ReadAllLines(resVerFile);
                    if (int.TryParse(lines[0], out var resVer))
                    {
                        Debug.Log($"old res ver: {resVer}");
                        resVer++;
                        resVerStr = $"{resVer}";
                        File.WriteAllText(resVerFile, resVerStr); //确保no bom
                    }
                }
                catch (Exception ex)
                {
                    Debug.LogError($"ResVer.bin出错");
                    return;
                }
            }
            else
            {
                File.WriteAllText(resVerFile, "1");
            }

            var versionsFile = sb.Append(buildOutputDir).Append("Versions.bin").ToString();
            sb.Clear();

            using (var sw = new StreamWriter(versionsFile, false, Encoding.UTF8)) //确保no bom
            {
                var dirName = di.Name;
                sw.WriteLine(resVerStr); //第1行版本号

                var crcTable = Crc32Utils.CreateCrcTable();
                var buf = new byte[1024];

                for (var i = 0; i < allFileInfos.Length; ++i)
                {
                    var fi = allFileInfos[i];
                    var fileName = fi.Name;
                    if (fileName != dirName
                        && !fileName.EndsWith(".bin", StringComparison.OrdinalIgnoreCase))
                        continue;

                    if ("Versions.bin" == fileName)
                        continue;

                    if ("ResVer.bin" == fileName)
                        continue;

                    var relativePath = sb.Append(fi.Name).Replace('\\', '/'); //.Replace(buildOutputDir, "");
                    var line = sb.Append('|').Append(fi.Length)
                        .Append('|').Append(Crc32Utils.FileCrc32(fi.FullName, crcTable, buf)) //crc
                        .Append('|').Append(0) //offset
                        .ToString();
                    sb.Clear();
                    sw.WriteLine(line);
                    Debug.Log($"line: {line}");
                }
            }
        }


        public static void DumpManualBundles()
        {
            var tempDict = new Dictionary<string, bool>();

            var bundleNames = AssetDatabase.GetAllAssetBundleNames();

            int count = 0;
            for (int i = 0, max = bundleNames.Length; i < max; ++i)
            {
                var bundleName = bundleNames[i];

                var title = $"正在处理: {i}/{max}";
                if (EditorUtility.DisplayCancelableProgressBar(title, bundleName, i / (float)max))
                    break;

                var bundleFiles = AssetDatabase.GetAssetPathsFromAssetBundle(bundleName);
                if (bundleFiles.Length <= 0)
                    continue;

                if (1 == bundleFiles.Length)
                {
                    if (bundleFiles[0].EndsWith("Panel.prefab", StringComparison.OrdinalIgnoreCase))
                        continue;
                }

                Debug.Log($"bundle: {bundleName} ==========");
                count++;
                for (var j = 0; j < bundleFiles.Length; ++j)
                {
                    var file = bundleFiles[j];
                    var dir = Path.GetDirectoryName(file);

                    Debug.Log($"{file}, {Utils.DirFilesHasMultiBundleName(tempDict, dir, bundleName)}");
                }

                Debug.Log($"bundle: {bundleName} ========== end");
            }

            Debug.Log($"bundle count: {count}");
            EditorUtility.ClearProgressBar();
        }


        public static bool DirFilesHasMultiBundleName(Dictionary<string, bool> tempDict, string dir, string bundleName)
        {
            //相同文件夹下是否还有其他bundle名
            if (!tempDict.TryGetValue(dir, out var dirHasMultiBundleName))
            {
                var subFiles = Directory.GetFiles(dir, "*.*", SearchOption.TopDirectoryOnly);
                for (var i = 0; i < subFiles.Length; ++i)
                {
                    var subFile = subFiles[i];
                    var importer = AssetImporter.GetAtPath(subFile) as AssetImporter;
                    if (null == importer)
                        continue;

                    if (importer.assetBundleName != bundleName)
                    {
                        tempDict[dir] = true;
                        return true;
                    }
                }

                return false;
            }

            return true;
        }


        public static T GetAsset<T>(string path) where T : ScriptableObject
        {
            var asset = AssetDatabase.LoadAssetAtPath<T>(path);
            if (asset == null)
            {
                asset = ScriptableObject.CreateInstance<T>(); //将类序列化成资源
                AssetDatabase.CreateAsset(asset, path);
                AssetDatabase.SaveAssets();
            }
            
            return asset;
        }


        /// <summary>
        /// 文件是否为资源类型. 非Assets目录下的资源和代码资源都会返回false
        /// </summary>
        public static bool ValidateAsset(string assetPath)
        {
            if (!assetPath.StartsWith("Assets/")) return false;

            //Editor资源
            if (assetPath.IndexOf("/Editor/") >= 0) return false;

            if (assetPath.LastIndexOf("示意图") >= 0)
                return false;

            var ext = Path.GetExtension(assetPath).ToLower();
            //不是脚本和.meta就是有效资源?
            switch (ext)
            {
            case ".dll":
            case ".cs":
            case ".meta":
            case ".js":
            case ".boo":
            return false;
            }

            return true;
        }


        public static void CheckArrayPropChange(SerializedProperty prop_array, List<int> tempDeleteList, List<int> tempMoveUpList, List<int> tempMoveDownList)
        {
            if (tempDeleteList.Count > 0)
            {
                for (var i = 0; i < tempDeleteList.Count; ++i)
                {
                    prop_array.DeleteArrayElementAtIndex(tempDeleteList[i]);
                }
                tempDeleteList.Clear();
            }

            if (tempMoveUpList.Count > 0)
            {
                for (var i = 0; i < tempMoveUpList.Count; ++i)
                {
                    var index = tempMoveUpList[i];
                    prop_array.MoveArrayElement(index, index - 1);
                }
                tempMoveUpList.Clear();
            }

            if (tempMoveDownList.Count > 0)
            {
                for (var i = 0; i < tempMoveDownList.Count; ++i)
                {
                    var index = tempMoveDownList[i];
                    prop_array.MoveArrayElement(index, index + 1);
                }
                tempMoveDownList.Clear();
            }
        }

        //public static bool LayoutPropertyFoldout(Dictionary<string, bool> expandDict, SerializedProperty property, string foldoutLabel)
        //{
        //    expandDict.TryGetValue(property.propertyPath, out var expand);
        //    expand = EditorGUILayout.Foldout(expand, foldoutLabel);
        //    expandDict[property.propertyPath] = expand;
        //    return expand;
        //}

        //public static bool PropertyFoldout(Dictionary<string, bool> expandDict, ref Rect tempPos, SerializedProperty property, string foldoutLabel)
        //{
        //    expandDict.TryGetValue(property.propertyPath, out var expand);
        //    expand = EditorGUI.Foldout(tempPos, expand, foldoutLabel);
        //    expandDict[property.propertyPath] = expand;
        //    return expand;
        //}

        public static string GetBuildPlatformName(BuildTarget target)
        {
            switch (target)
            {
            case BuildTarget.Android:
                return "Android";
            //case BuildTarget.iPhone:
            case BuildTarget.iOS:
                return "iOS";
            case BuildTarget.WebGL:
                return "WebGL";
            case BuildTarget.StandaloneWindows:
            case BuildTarget.StandaloneWindows64:
                return "Windows";
#if UNITY_2017_3_OR_NEWER
            case BuildTarget.StandaloneOSX:
                return "OSX";
#else
                case BuildTarget.StandaloneOSXIntel:
                case BuildTarget.StandaloneOSXIntel64:
                case BuildTarget.StandaloneOSXUniversal:
                    return "OSX";
#endif
            }
            
            return null;
        }


        public static string GetRunPlatformName()
        {
            switch (Application.platform)
            {
            case RuntimePlatform.OSXPlayer:
                return "OSX";
            case RuntimePlatform.Android:
                return "Android";
            case RuntimePlatform.IPhonePlayer:
                return "iOS";
            case RuntimePlatform.WindowsPlayer:
#if !UNITY_5_4_OR_NEWER
                    case RuntimePlatform.WindowsWebPlayer:
#endif
                return "Windows";
            }

            return null;
        }


    } //end of class


}
